package app

import (
	"errors"
	"reflect"

	"gitee.com/tomatomeatman/golang-repository/bricks/model/dbinfo"
	"gitee.com/tomatomeatman/golang-repository/bricks/model/emity"
	"gitee.com/tomatomeatman/golang-repository/bricks/utils/ginutil"
)

// web控制层接口定义,用于规范控制层结构体
type Controller interface {
	GetModuleEntity(control Controller) (dbinfo.Entity, error) //对应模块数据实体
	GetModuleService(control Controller) (Service, error)      //对应模块业务实体
	RegisterUrl()                                              //接口注册
	Enable() int                                               //控制操作,首位9不参与用7个数代表开关,0为不限制,1为限制
	CheckRepeatCombination() []string                          //检查待新增内容是否存在重复数据(多字段组合重复即重复)集合
	CheckRepeatAlone() map[string]int                          //检查待新增内容是否存在重复数据(单独字段重复即重复)集合,注意:int必须是1、10、100、1000
	IdValuePrefix() string                                     //记录编号值前缀,此属性用于给id字段添加前缀,以便于在分布式系统中进行数据合并,注意:前缀只有1个字符
	LikeTimeLimit() float64                                    //模糊查询时是否要进行时间范围限制,默认900000天内,已经相当于不限制了
}

// we业务层接口定义,用于规范控制层结构体
type Service interface {

	/**
	* 取对应模块数据层实体,若子类未设置则返回DaoBaseFunc
	 */
	GetModuleDao() (Dao, error) //对应模块数据层实体

	/**
	 * 验证新增数据是否存在重复 (一旦使用则覆盖通用方法)
	 * @param ctx gin请求对象
	 * @param dbEntity 验证数据
	 * @return *MsgEmity 返回验证结果
	 */
	CheckRepeatByAdd(ctx ginutil.Context, dbEntity dbinfo.Entity) *emity.MsgEmity

	/**
	 * 验证更新数据是否存在重复 (一旦使用则覆盖通用方法)
	 * @param ctx gin请求对象
	 * @param dbEntity 待验证数据
	 * @return *MsgEmity 返回验证结果
	 */
	CheckRepeatByEdit(ctx ginutil.Context, dbEntity dbinfo.Entity) *emity.MsgEmity

	/**
	 * 新增
	 * entity 检查用数据结构
	 * data 数据
	 */
	Add(ctx ginutil.Context, entity dbinfo.Entity, data map[string]interface{}) *emity.MsgEmity

	/**
	 * 新增普通数据
	 * entity 检查用数据结构
	 * data 数据
	 */
	AddCommon(ctx ginutil.Context, entity dbinfo.Entity, aData map[string]interface{}) *emity.MsgEmity

	/**
	 * 新增树节点
	 * entity 检查用数据结构
	 * data 数据
	 */
	AddNode(ctx ginutil.Context, entity dbinfo.Entity, aData map[string]interface{}) *emity.MsgEmity

	// 批量新增
	Adds(ctx ginutil.Context, entitys []dbinfo.Entity, list []map[string]interface{}) *emity.MsgEmity

	// 批量新增
	AddList(ctx ginutil.Context, entitys []dbinfo.Entity) *emity.MsgEmity

	/**
	 * 修改状态
	 * @param entity 实体类
	 * @param id 编号
	 * @param iState 状态值
	 * @param iVersion 记录版本号
	 * @param sMemo 备注
	 * @param unidirectional 是否单向 设置为单向则新值必须大于旧值才能执行
	 * @return emity.MsgEmity 返回执行情况
	 */
	ChangeState(ctx ginutil.Context, entity dbinfo.Entity, id interface{}, iState int, iVersion int, sMemo string, unidirectional bool) *emity.MsgEmity

	/**
	 * 修改步骤值(如果设置为单向则新值必须大于旧值)
	 * @param id 编号
	 * @param iSetp 步骤值
	 * @param iVersion 记录版本号
	 * @param sMemo 备注
	 * @param unidirectional 是否单向 设置为单向则新值必须大于旧值才能执行
	 * @param entity 实体类
	 * @return emity.MsgEmity 返回执行情况
	 */
	ChangeSetp(ctx ginutil.Context, entity dbinfo.Entity, id interface{}, iSetp int, iVersion int, sMemo string, unidirectional bool) *emity.MsgEmity

	/**
	 * 删除
	 * @param entity 对象类型
	 * @param id 记录编号值
	 * @param iVersion 记录版本号
	 * @return emity.MsgEmity
	 */
	Del(ctx ginutil.Context, entity dbinfo.Entity, id interface{}, iVersion int) *emity.MsgEmity

	/**
	 * 删除
	 * @param entity 对象类型
	 * @param where 执行条件
	 * @return emity.MsgEmity
	 */
	DelByMap(ctx ginutil.Context, entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo) *emity.MsgEmity

	/**
	 * 按实体保留map中的数据
	 * entity 参考的结构体
	 * data 数据
	 */
	HoldByEntity(entity dbinfo.Entity, data map[string]interface{}) map[string]interface{}

	/**
	 * 修改
	 * @param entity 对象类型
	 * @param id 记录编号值
	 * @param iVersion 记录版本号
	 * @param data 待更新的字段和值
	 * @return emity.MsgEmity
	 */
	Edit(ctx ginutil.Context, entity dbinfo.Entity, id interface{}, iVersion int, aData map[string]interface{}) *emity.MsgEmity

	/**
	 * 根据主键查询数据
	 * id 主键
	 * entity 检查用数据结构
	 */
	FindById(ctx ginutil.Context, entity dbinfo.Entity, id interface{}) *emity.MsgEmity

	// 查询所有数据
	FindAll(ctx ginutil.Context, entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo) *emity.MsgEmity

	// 查询指定时间内数据
	FindByDate(ctx ginutil.Context, entity dbinfo.Entity, sDateSt string, sDateEd string) *emity.MsgEmity

	// 查询指定行数据
	FindByRow(ctx ginutil.Context, entity dbinfo.Entity, id interface{}) *emity.MsgEmity

	// 查询分页数据
	FindByPage(ctx ginutil.Context, entity dbinfo.Entity, findByPageParam dbinfo.FindByPageParam) *emity.MsgEmity

	/**
	 * 补充数据库实体类的数据--新增
	 * @param dbEntity
	 * @param selfId 自提供的编号,防止从序列中获取
	 * @param idValuePrefix Id前缀
	 * @return
	 */
	SupplyDbEntityAttrByAdd(ctx ginutil.Context, dbEntity dbinfo.Entity, selfId string, idValuePrefix string) *emity.MsgEmity

	/**
	 * 验证新增数据是否存在重复
	 *
	 */
	ValidEntityRepeatByAdd(ctx ginutil.Context, dbEntity dbinfo.Entity) *emity.MsgEmity

	/**
	 * 验证更新数据是否存在重复
	 *
	 */
	ValidEntityRepeatByEdit(ctx ginutil.Context, entity dbinfo.Entity, id interface{}, data map[string]interface{}) *emity.MsgEmity

	/**
	 * 通用树型结构表添加数据时重复检查方法
	 * dbEntity
	 */
	CommonCheckRepeatByAddAndTree(ctx ginutil.Context, dbEntity dbinfo.Entity) *emity.MsgEmity

	/**
	 * 通用树型结构表添加数据时重复检查方法
	 * entity
	 */
	CommonCheckRepeatByEditAndTree(ctx ginutil.Context, entity dbinfo.Entity, id interface{}, sName interface{}) *emity.MsgEmity

	/**
	 * 通用添加数据时重复检查方法
	 * dbEntity
	 */
	CommonCheckRepeatByAdd(ctx ginutil.Context, dbEntity dbinfo.Entity) *emity.MsgEmity

	/**
	 * 通用更新数据时重复检查方法
	 * entity
	 */
	CommonCheckRepeatByEdit(ctx ginutil.Context, entity dbinfo.Entity, id interface{}, data map[string]interface{}) *emity.MsgEmity

	/**
	 * 读取树形结构数据
	 * @param entity
	 * @param sGroupColumn
	 * @param sGroupName
	 * @return
	 */
	FindByTree(ctx ginutil.Context, entity dbinfo.Entity, sGroupColumn, sGroupName string) *emity.MsgEmity

	/**
	 * List转树形结构
	 * @param source Map或切片结构
	 * @param rootName
	 * @param idFieldName
	 * @param pIdFieldName
	 * @param childFieldName
	 * @return
	 */
	CreateTree(source interface{}, rootName, idFieldName, pIdFieldName, childFieldName string) *emity.MsgEmity

	/**
	 * List转树形结构
	 * @param source 切片结构
	 * @param rootName
	 * @param idFieldName
	 * @param pIdFieldName
	 * @param childFieldName
	 * @return
	 */
	createTreeByList(source []interface{},
		rootName, idFieldName, pIdFieldName, childFieldName string) *emity.MsgEmity

	/**
	 * List转树形结构
	 * @param source Map结构
	 * @param rootName
	 * @param idFieldName
	 * @param pIdFieldName
	 * @param childFieldName
	 * @return
	 */
	createTreeByMap(source []map[string]interface{},
		rootName, idFieldName, pIdFieldName, childFieldName string) *emity.MsgEmity

	/**
	 * 根据字段名取指定记录编号的数据库表中对应字段的值
	 * @param entity 实体类
	 * @param id
	 * @param fieldNames 待取数据的字段名称集合
	 * @return emity.MsgEmity 返回内容data中存放的是Map
	 */
	GetValueByFieldName(ctx ginutil.Context, entity dbinfo.Entity, id interface{}, fieldNames []string) *emity.MsgEmity

	/**
	 * 根据字段名取指定记录编号的数据库表中对应字段的值
	 * @param entity 实体类
	 * @param id
	 * @param fieldName 待取数据的字段名称集合
	 * @return emity.MsgEmity 返回内容data中存放的是Map
	 */
	GetValueByField(ctx ginutil.Context, entity dbinfo.Entity, id interface{}, fieldName string) *emity.MsgEmity

	/**
	 * 根据字段名取指定条件的数据库表中对应字段的值
	 * @param entity 实体类
	 * @param whereInfo 条件
	 * @param fieldName 待取数据的字段名称集合
	 * @param currentUser 当前用户
	 * @return emity.MsgEmity 返回内容data中存放的是Map
	 */
	GetValueByWhere(ctx ginutil.Context, entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, fieldName string) *emity.MsgEmity

	/**
	 * 取记录对应的版本号
	 * @param entity 实体类
	 * @param idName 编号
	 * @return
	 */
	GetiVersion(ctx ginutil.Context, entity dbinfo.Entity, id interface{}) *emity.MsgEmity

	/**
	 * 取记录对应的状态值
	 * @param entity 实体类
	 * @param idName 编号
	 * @return
	 */
	GetiState(ctx ginutil.Context, entity dbinfo.Entity, id interface{}) *emity.MsgEmity

	/**
	 * 根据关键值取对象集合
	 * @Param entity 实体类
	 * @Param where 存放查询条件
	 * @return emity.MsgEmity
	 */
	FindByKey(ctx ginutil.Context, entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo) *emity.MsgEmity

	/**
	 * 根据关键值取对象集合中的第一个
	 * @Param entity 实体类
	 * @Param where 存放查询条件
	 * @param fields 指定要查询的字段集合
	 * @return emity.MsgEmity
	 */
	FindOneByKey(ctx ginutil.Context, entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, fields ...string) *emity.MsgEmity

	/**
	 * 根据关键值取对象集合中的符合条件的第一条记录的指定字段
	 * @Param entity 实体类
	 * @Param where 存放查询条件
	 * @param fieldName 指定要查询的字段
	 * @return emity.MsgEmity
	 */
	FindValueByKey(ctx ginutil.Context, entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, fieldName string) *emity.MsgEmity

	/**
	 * 根据指定字段进行分组查询
	 * @Param entity 实体类
	 * @Param where 存放查询条件
	 * @param fieldMap 指定要查询的字段集合(原字段, 别名)
	 * @return emity.MsgEmity
	 */
	FindByFields(ctx ginutil.Context, entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, fieldMap map[string]string) *emity.MsgEmity

	/**
	 * 根据关键值查数量
	 * @Param entity 实体类
	 * @Param where 存放查询条件
	 * @return emity.MsgEmity
	 */
	FindCountByKey(ctx ginutil.Context, entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo) *emity.MsgEmity

	/**
	 * 根据字段名取分组数据
	 * @param entity 实体类
	 * @param sCreator 指定用户
	 * @param fields 字段名与别名对象
	 * @return
	 */
	GroupByField(ctx ginutil.Context, entity dbinfo.Entity, sCreator string, fields map[string]string) *emity.MsgEmity

	/**
	 * 根据字段名取分组数据及分组后数量
	 * @param entity 实体类
	 * @param sCreator 指定用户
	 * @param fields 字段名与别名对象
	 * @return
	 */
	GroupByFieldAndCount(ctx ginutil.Context, entity dbinfo.Entity, sCreator string, fields map[string]string) *emity.MsgEmity

	/**
	 * 取表中指定字段的最大值
	 * @param entity 实体类
	 * @param sCreator 指定用户
	 * @param field 字段名
	 * @param where 查询条件字符串
	 * @return emity.MsgEmity
	 */
	MaxByField(ctx ginutil.Context, entity dbinfo.Entity, sCreator string, field string, whereInfo []dbinfo.WhereInfo) *emity.MsgEmity

	/**
	 * 取表中指定字段的最小值
	 * @param entity 实体类
	 * @param sCreator 指定用户
	 * @param field 字段名
	 * @param where 查询条件
	 * @return emity.MsgEmity
	 */
	MinByField(ctx ginutil.Context, entity dbinfo.Entity, sCreator string, field string, whereInfo []dbinfo.WhereInfo) *emity.MsgEmity

	/**
	 * 检查关键值记录是否存在(返回1:存在;0:不存在)
	 * @param entity 实体类
	 * @Param id
	 * @return emity.MsgEmity
	 */
	HasById(ctx ginutil.Context, entity dbinfo.Entity, id interface{}) *emity.MsgEmity

	/**
	 * 检查关键值记录是否存在(返回1:存在;0:不存在)
	 * @param entity 实体类
	 * @Param keyName 字段名
	 * @Param keyValue 字段值
	 * @return emity.MsgEmity
	 */
	HasByKey(ctx ginutil.Context, entity dbinfo.Entity, keyName string, keyValue interface{}) *emity.MsgEmity

	/**
	 * 清理指定用户的缓存
	 * @param cacheName 缓存名
	 * @Param sUser 用户名
	 * @return emity.MsgEmity
	 */
	ClearCache(ctx ginutil.Context, cacheName string, sUser string) *emity.MsgEmity

	/**
	 * 查询组结构数据
	 * @param ctx Http请求对象
	 * @param entity 实体类
	 * @param sGroupColumn 分组名(树节点)所在字段名
	 * @param sGroupName 分组名(树节点)
	 * @return
	 */
	FindByGroup(ctx ginutil.Context, entity dbinfo.Entity, sGroupColumn, sGroupName string) *emity.MsgEmity

	/**
	 * 添加数据到指定组下
	 * 警告:对象必须符合树形结构要求,如:sId、sPid
	 * @param ctx Http请求对象
	 * @param sGroupName 分组字段名称(树节点)
	 * @param sGroupValue 分组字段值(树节点)
	 * @param entity 实体对象
	 * @return
	 */
	AddToGroup(ctx ginutil.Context, entity dbinfo.Entity, sGroupName, sGroupValue string) *emity.MsgEmity

	/**
	 * 执行SQL脚本获取单行单列数据
	 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录且为单列
	 * @param sql 待执行的SQL脚本
	 * @return emity.MsgEmity
	 */
	DoSql(sql string) *emity.MsgEmity

	/**
	 * 执行SQL脚本获取单行单列数据
	 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录且为单列
	 * @param sql 待执行的SQL脚本
	 * @return emity.MsgEmity
	 */
	ExecSql(sql string) *emity.MsgEmity

	/**
	 * 执行SQL脚本获取单行单列数据
	 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录且为单列
	 * @param sql 待执行的SQL脚本
	 * @return emity.MsgEmity
	 */
	GetValue(sql string) *emity.MsgEmity

	/**
	 * 执行SQL脚本获取一行数据(多列)
	 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录
	 * @param sql 待执行的SQL脚本
	 * @return emity.MsgEmity
	 */
	GetRow(sql string) *emity.MsgEmity

	/**
	 * 执行SQL脚本获取多行数据(多列)
	 * 注意:库名必须用${}进行包装,此脚本可返回多条记录
	 * @param sql SQL脚本
	 * @return emity.MsgEmity
	 */
	GetRows(sql string) *emity.MsgEmity

	/**
	 * 根据关键值翻转值(限布尔值类型,1转2,2转1)
	 * 警告:此方法只支持布尔值类型,且只支持翻转1和2
	 * @Param ctx http请求对象
	 * @Param entity 实体类
	 * @Param whereInfo 存放查询条件
	 * @Param reversalColumn 翻转的字段名
	 * @return emity.MsgEmity
	 */
	ReversalByKey(ctx ginutil.Context, entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, reversalColumn string) *emity.MsgEmity

	/**
	 * 根据条件仅查询指定字段名数据
	 * @param entity 实体类
	 * @param whereInfo
	 * @param fieldNames 待取数据的字段名称集合
	 * @return emity.MsgEmity 返回内容data中存放的是Map
	 */
	FindField(ctx ginutil.Context, entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, fieldNames []string) *emity.MsgEmity

	/**
	 * 上传文件
	 * @param ctx http请求对象
	 * @param modelName 模块名称
	 * @return emity.MsgEmity
	 */
	UpFile(ctx ginutil.Context, modelName string) *emity.MsgEmity

	/**
	 * 获取图片
	 * @param ctx http请求对象
	 * @param modelName 模块名称
	 * @param filename 文件名
	 */
	LookImg(ctx ginutil.Context, modelName, filename string)
}

// we数据层接口定义,用于规范控制层结构体
type Dao interface {

	/**
	 * 新增
	 * @param entity 待保存实体
	 */
	Add(entity dbinfo.Entity) *emity.MsgEmity

	/**
	 * 通用新增数据方法
	 * @param entity 待保存实体
	 */
	AddCommon(entity dbinfo.Entity) *emity.MsgEmity

	/**
	 * 新增树节点
	 * @param entity 检查用数据结构
	 */
	AddNode(entity dbinfo.Entity) *emity.MsgEmity

	// 批量新增
	Adds(entitys []dbinfo.Entity) *emity.MsgEmity

	/**
	 * 修改状态
	 * @param entity 实体类
	 * @param id 编号
	 * @param iState 状态值
	 * @param iVersion 记录版本号
	 * @param sMemo 备注
	 * @param unidirectional 是否单向 设置为单向则新值必须大于旧值才能执行
	 * @return emity.MsgEmity 返回执行情况
	 */
	ChangeState(entity dbinfo.Entity, id interface{}, iState int, iVersion int, sMemo string, unidirectional bool) *emity.MsgEmity

	/**
	 * 修改步骤值(如果设置为单向则新值必须大于旧值)
	 * @param id 编号
	 * @param iSetp 步骤值
	 * @param iVersion 记录版本号
	 * @param sMemo 备注
	 * @param unidirectional 是否单向 设置为单向则新值必须大于旧值才能执行
	 * @param entity 实体类
	 * @return emity.MsgEmity 返回执行情况
	 */
	ChangeSetp(entity dbinfo.Entity, id interface{}, iSetp int, iVersion int, sMemo string, unidirectional bool) *emity.MsgEmity

	// 逻辑删除(非物理删除)
	DelSign(entity dbinfo.Entity, id interface{}, iVersion int, currentUser string, onlyCreator bool) *emity.MsgEmity

	// 逻辑删除(非物理删除)
	DelSignByMap(entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, currentUser string, onlyCreator bool) *emity.MsgEmity

	// 删除
	Del(entity dbinfo.Entity, id interface{}, iVersion int, currentUser string, onlyCreator bool) *emity.MsgEmity

	// 删除
	DelByMap(entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 修改
	 * @param entity 对象类型
	 * @param id 记录编号值
	 * @param iVersion 记录版本号
	 * @param data 待更新的字段和值
	 * @param currentUser 当前用户
	 * @param onlyCreator 仅创建用户
	 * @return emity.MsgEmity
	 */
	Edit(entity dbinfo.Entity, id interface{}, iVersion int, data map[string]interface{}, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 根据主键查询数据
	 * @param entity 检查用数据结构
	 * @param id 主键
	 * @param currentUser 当前用户
	 * @param onlyCreator 仅创建用户
	 * @return emity.MsgEmity
	 */
	FindById(entity dbinfo.Entity, id interface{}, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 根据主键查询数据(返回结构体数据)
	 * @param entity 检查用数据结构
	 * @param id 主键
	 * @param currentUser 当前用户
	 * @param onlyCreator 仅创建用户
	 * @return emity.MsgEmity
	 */
	EntityById(entity dbinfo.Entity, id interface{}, currentUser string, onlyCreator bool) *emity.MsgEmity

	EntityBySql(entityList interface{}, sql string, where map[string]interface{}) *emity.MsgEmity

	/**
	 * 查询所有数据
	 * @param entity 检查用数据结构
	 * @param where 查询条件
	 * @param currentUser 当前用户
	 * @param onlyCreator 仅创建用户
	 * @return emity.MsgEmity
	 */
	FindAll(entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 查询指定时间内数据
	 * @param entity 检查用数据结构
	 * @param sDateSt 开始时间
	 * @param sDateEd 结束时间
	 * @param currentUser 当前用户
	 * @param onlyCreator 仅创建用户
	 * @return emity.MsgEmity
	 */
	FindByDate(entity dbinfo.Entity, sDateSt string, sDateEd string, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 查询指定行数据
	 * @param entity 检查用数据结构
	 * @param id 记录编号
	 * @param currentUser 当前用户
	 * @param onlyCreator 仅创建用户
	 * @return emity.MsgEmity
	 */
	FindByRow(entity dbinfo.Entity, id interface{}, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 查询分页数据
	 * @param entity 检查用数据结构
	 * @param findByPageParam 分页参数
	 * @param currentUser 当前用户
	 * @param onlyCreator 仅创建用户
	 * @return emity.MsgEmity
	 */
	FindByPage(entity dbinfo.Entity, findByPageParam dbinfo.FindByPageParam, currentUser string, onlyCreator bool) *emity.MsgEmity

	// 取路径字段
	GetPath(sId, dbName, tableName string) string

	/**
	 * 取指定节点下的子节点编号
	 * @param tableInfo 表信息
	 * @param sPid 父节点
	 * @return
	 */
	NewChildId(tableInfo *dbinfo.TableInfo, sPid string) *emity.MsgEmity

	/**
	 * 验证新增数据是否存在重复
	 * @param dbEntity 数据实体
	 * @param currentUser 当前用户
	 * @return emity.MsgEmity
	 */
	ValidEntityRepeatByAdd(dbEntity dbinfo.Entity, currentUser string) *emity.MsgEmity

	/**
	 * 验证更新数据是否存在重复
	 * @param dbEntity 数据实体
	 * @param id 主键
	 * @param data 数据
	 * @param currentUser 当前用户
	 * @return emity.MsgEmity
	 */
	ValidEntityRepeatByEdit(entity dbinfo.Entity, id interface{}, data map[string]interface{}, currentUser string) *emity.MsgEmity

	/**
	 * 通用树型结构表添加数据时重复检查方法
	 * @param dbEntity 数据实体
	 * @param currentUser 当前用户
	 * @return emity.MsgEmity
	 */
	CommonCheckRepeatByAddAndTree(dbEntity dbinfo.Entity, currentUser string) *emity.MsgEmity

	/**
	 * 通用树型结构表添加数据时重复检查方法
	 * @param dbEntity 数据实体
	 * @param id 主键
	 * @param sName 展现名
	 * @param currentUser 当前用户
	 * @return emity.MsgEmity
	 */
	CommonCheckRepeatByEditAndTree(entity dbinfo.Entity, id interface{}, sName interface{}, currentUser string) *emity.MsgEmity

	/**
	 * 通用添加数据时重复检查方法
	 * @param dbEntity 数据实体
	 * @param currentUser 当前用户
	 * @return emity.MsgEmity
	 */
	CommonCheckRepeatByAdd(dbEntity dbinfo.Entity, currentUser string) *emity.MsgEmity

	/**
	 * 通用更新数据时重复检查方法
	 * @param entity 数据实体
	 * @param id 数据主键
	 * @param currentUser 当前用户
	 * @return emity.MsgEmity
	 */
	CommonCheckRepeatByEdit(entity dbinfo.Entity, id interface{}, currentUser string) *emity.MsgEmity

	/**
	 * 读取树形结构数据
	 * @param entity 数据实体
	 * @param sGroupColumn 分组字段
	 * @param sGroupName 分组名称
	 * @param currentUser 当前用户
	 * @return emity.MsgEmity
	 */
	FindByTree(entity dbinfo.Entity, sGroupColumn, sGroupName string, currentUser string) *emity.MsgEmity

	/**
	 * 根据字段名取指定记录编号的数据库表中对应字段的值
	 * @param entity 实体类
	 * @param id 记录编号
	 * @param fieldNames 待取数据的字段名称集合
	 * @param currentUser 当前用户
	 * @Param onlyCreator 是否只取当前用户创建的数据
	 * @return emity.MsgEmity 返回内容data中存放的是Map
	 */
	GetValueByFieldName(entity dbinfo.Entity, id interface{}, fieldNames []string, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 根据字段名取指定记录编号的数据库表中对应字段的值
	 * @param entity 实体类
	 * @param id 记录编号
	 * @param fieldName 待取数据的字段名称集合
	 * @param currentUser 当前用户
	 * @Param onlyCreator 是否只取当前用户创建的数据
	 * @return emity.MsgEmity 返回内容data中存放的是Map
	 */
	GetValueByField(entity dbinfo.Entity, id interface{}, fieldName, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 根据字段名取指定条件的数据库表中对应字段的值
	 * @param entity 实体类
	 * @param whereInfo 条件
	 * @param fieldName 待取数据的字段名称集合
	 * @param currentUser 当前用户
	 * @Param onlyCreator 是否只取当前用户创建的数据
	 * @return emity.MsgEmity 返回内容data中存放的是Map
	 */
	GetValueByWhere(entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, fieldName, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 取记录对应的版本号
	 * @param entity 实体类
	 * @param idName 编号
	 * @return
	 */
	GetiVersion(entity dbinfo.Entity, id interface{}) *emity.MsgEmity

	/**
	 * 取记录对应的状态值
	 * @param entity 实体类
	 * @param id 编号
	 * @return
	 */
	GetiState(entity dbinfo.Entity, id interface{}) *emity.MsgEmity

	/**
	 * 根据关键值取对象集合
	 * @Param entity 实体类
	 * @Param where 存放查询条件
	 * @Param currentUser 当前用户
	 * @Param onlyCreator 是否只取当前用户创建的数据
	 * @return emity.MsgEmity
	 */
	FindByKey(entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 根据关键值取对象集合中的第一个
	 * @Param entity 实体类
	 * @Param where 存放查询条件
	 * @Param currentUser 当前用户
	 * @param onlyCreator 是否只取当前用户创建的数据
	 * @param fields 指定要查询的字段集合
	 * @return emity.MsgEmity
	 */
	FindOneByKey(entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, currentUser string, onlyCreator bool, fields ...string) *emity.MsgEmity

	/**
	 * 根据关键值取对象集合中的符合条件的第一条记录的指定字段
	 * @Param entity 实体类
	 * @Param where 存放查询条件
	 * @param fieldName 指定要查询的字段
	 * @param currentUser 当前用户
	 * @param onlyCreator 仅查询创建者
	 * @return emity.MsgEmity
	 */
	FindValueByKey(entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, fieldName string, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 根据关键值取对象集合中的符合条件的第一条记录的指定字段
	 * @Param entity 实体类
	 * @Param where 存放查询条件
	 * @param fieldMap 指定要查询的字段集合(原字段, 别名)
	 * @param currentUser 当前用户
	 * @param onlyCreator 仅查询创建者
	 * @return emity.MsgEmity
	 */
	FindByFields(entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, fieldMap map[string]string, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 根据关键值查数量
	 * @Param entity 实体类
	 * @Param where 存放查询条件
	 * @param currentUser 当前用户
	 * @param onlyCreator 仅查询创建者
	 * @return emity.MsgEmity
	 */
	FindCountByKey(entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 以事务方式执行多个sql
	 * 注意:Mapper必须存在才能执行
	 * @param sqls [sql, params]
	 * @return emity.MsgEmity 一个执行失败则回滚
	 */
	TransactionSql(sqls map[string]map[string]interface{}) *emity.MsgEmity

	/**
	 * 根据字段名取分组数据
	 * @param entity 实体类
	 * @param sCreator 指定用户
	 * @param fields 字段名与别名对象
	 * @param currentUser 当前用户
	 * @param onlyCreator 用户查询限制(仅创建者可见)
	 * @return
	 */
	GroupByField(entity dbinfo.Entity, sCreator string, fields map[string]string, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 根据字段名取分组数据,并返回数量
	 * @param entity 实体类
	 * @param sCreator 指定用户
	 * @param fields 字段名与别名对象
	 * @param currentUser 当前用户
	 * @param onlyCreator 用户查询限制(仅创建者可见)
	 * @return
	 */
	GroupByFieldAndCount(entity dbinfo.Entity, sCreator string, fields map[string]string, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 根据字段名取分组数据
	 * @param entity 实体类
	 * @param sCreator 指定用户
	 * @param fields 字段名与别名对象
	 * @param currentUser 当前用户
	 * @param onlyCreator 用户查询限制(仅创建者可见)
	 * @param isGroupCount 添加分组后是否添加'数量列'
	 * @return
	 */
	GroupByFieldBase(entity dbinfo.Entity, sCreator string, fields map[string]string, currentUser string, onlyCreator, isGroupCount bool) *emity.MsgEmity

	/**
	 * 取表中指定字段的最大值
	 * @param entity 实体类
	 * @param sCreator 指定用户
	 * @param field 字段名
	 * @param where 查询条件
	 * @param currentUser 当前用户
	 * @param onlyCreator 用户查询限制(仅创建者可见)
	 * @return emity.MsgEmity
	 */
	MaxByField(entity dbinfo.Entity, sCreator string, field string, whereInfo []dbinfo.WhereInfo, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 取表中指定字段的最小值
	 * @param entity 实体类
	 * @param sCreator 指定用户
	 * @param field 字段名
	 * @param where 查询条件
	 * @param currentUser 当前用户
	 * @param onlyCreator 用户查询限制(仅创建者可见)
	 * @param whereStr 查询条件字符串
	 * @return
	 */
	MinByField(entity dbinfo.Entity, sCreator string, field string, whereInfo []dbinfo.WhereInfo, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	 * 检查关键值记录是否存在(返回1:存在;0:不存在)
	 * @param entity 实体类
	 * @param id 记录编号
	 * @return emity.MsgEmity
	 */
	HasById(entity dbinfo.Entity, id interface{}) *emity.MsgEmity

	/**
	 * 检查关键值记录是否存在(返回1:存在;0:不存在)
	 * @param entity 实体类
	 * @Param keyName 字段名
	 * @Param keyValue 字段值
	 * @return emity.MsgEmity
	 */
	HasByKey(entity dbinfo.Entity, keyName string, keyValue interface{}) *emity.MsgEmity

	/**
	 * 执行SQL脚本获取单行单列数据
	 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录且为单列
	 * @param sql 待执行的SQL脚本
	 * @param where 存放查询条件
	 * @return emity.MsgEmity
	 */
	DoSql(sql string, where ...interface{}) *emity.MsgEmity

	/**
	 * 执行SQL脚本获取单行单列数据
	 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录且为单列
	 * @param sql 待执行的SQL脚本
	 * @param where 存放查询条件
	 * @return emity.MsgEmity
	 */
	ExecSql(sql string, where ...interface{}) *emity.MsgEmity

	/**
	 * 执行SQL脚本获取单行单列数据
	 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录且为单列
	 * @param sql 待执行的SQL脚本
	 * @param where 存放查询条件
	 * @return emity.MsgEmity
	 */
	GetValue(sql string, where ...interface{}) *emity.MsgEmity

	/**
	 * 执行SQL脚本获取一行数据(多列)
	 * 注意:库名必须用${}进行包装,此脚本应只存在一条记录
	 * @param sql 待执行的SQL脚本
	 * @param where 存放查询条件
	 * @return emity.MsgEmity
	 */
	GetRow(sql string, where ...interface{}) *emity.MsgEmity

	/**
	 * 执行SQL脚本获取多行数据(多列)
	 * 注意:库名必须用${}进行包装,此脚本可返回多条记录
	 * @param sql SQL脚本
	 * @param where 存放查询条件
	 * @return emity.MsgEmity
	 */
	GetRows(sql string, where ...interface{}) *emity.MsgEmity

	/**
	 * 根据关键值翻转值(限布尔值类型,1转2,2转1)
	 * @Param entity 实体类
	 * @Param whereInfo 存放查询条件
	 * @Param reversalColumn 翻转的字段名
	 * @Param currentUser 当前用户
	 * @Param onlyCreator 是否只翻转创建人创建的数据
	 * @return emity.MsgEmity
	 */
	ReversalByKey(entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, reversalColumn, currentUser string, onlyCreator bool) *emity.MsgEmity

	/**
	* 根据条件仅查询指定字段名数据
	* @param entity 实体类
	* @param whereInfo
	* @param fieldNames 待取数据的字段名称集合
	* @Param currentUser 当前用户
	* @Param onlyCreator 是否只翻转创建人创建的数据
	* @return emity.MsgEmity 返回内容data中存放的是Map
	 */
	FindField(entity dbinfo.Entity, whereInfo []dbinfo.WhereInfo, fieldNames []string, currentUser string, onlyCreator bool) *emity.MsgEmity
}

type ControllerBaseFunc struct{}

type ServiceBaseFunc = CommonService

type DaoBaseFunc = CommonDao

// ---------------- 控制层默认接口实现 ----------------//

// 接口注册
func (control ControllerBaseFunc) RegisterUrl() {
	//子类实现
}

// -- 控制操作,首位9不参与用7个数代表开关,0为不限制,1为限制 --//
// -- 7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除 --//
// -- 其中前5个为'是否仅创建者可操作'后续为其它控制开关 --//
func (control ControllerBaseFunc) Enable() int {
	return 90000001
}

// 检查待新增内容是否存在重复数据(多字段组合重复即重复)集合
func (control ControllerBaseFunc) CheckRepeatCombination() []string {
	return []string{}
}

// -- 检查待新增内容是否存在重复数据(单独字段重复即重复)集合,注意:int必须是1、10、100、1000 --//
func (control ControllerBaseFunc) CheckRepeatAlone() map[string]int {
	return map[string]int{}
}

func (control ControllerBaseFunc) IdValuePrefix() string {
	return ""
}

func (control ControllerBaseFunc) LikeTimeLimit() float64 {
	return 900000
}

func (control *ControllerBaseFunc) GetModuleEntity(controller Controller) (dbinfo.Entity, error) {
	moduleValue := reflect.ValueOf(controller).Elem().FieldByName("ModuleEntity")

	if moduleValue.Kind() != reflect.Ptr && moduleValue.Kind() != reflect.Struct {
		return nil, errors.New("未设置模块数据实体")
	}

	// 获取 Entity 的反射值

	var entityElem reflect.Value
	if moduleValue.Kind() == reflect.Ptr {
		entityElem = reflect.New(moduleValue.Type().Elem())
	} else {
		entityElem = reflect.New(moduleValue.Type())
	}

	entityValue := entityElem.Interface().(dbinfo.Entity)

	return entityValue, nil
}

func (control *ControllerBaseFunc) GetModuleService(controller Controller) (Service, error) {
	moduleValue := reflect.ValueOf(controller).Elem().FieldByName("ModuleService")

	if moduleValue.Kind() != reflect.Ptr && moduleValue.Kind() != reflect.Struct {
		return &ServiceBaseFunc{}, errors.New("未设置模块业务实体")
	}

	// 获取 Service 的反射值
	var serviceElem reflect.Value
	if moduleValue.Kind() == reflect.Ptr {
		serviceElem = reflect.New(moduleValue.Type().Elem())
	} else {
		serviceElem = reflect.New(moduleValue.Type())
	}

	service := serviceElem.Interface().(Service)

	return service, nil
}

// ---------------- 业务层默认接口实现 ----------------//

/**
 * 取对应模块数据层实体
 */
func (service *ServiceBaseFunc) GetModuleDao() (Dao, error) {
	moduleValue := reflect.ValueOf(service).Elem().FieldByName("ModuleDao")

	if moduleValue.Kind() != reflect.Ptr || moduleValue.Type().Elem().Kind() != reflect.Struct {
		return &DaoBaseFunc{}, nil //未设置模块数据层实体
	}

	// 获取 Entity 的反射值
	daoElem := moduleValue.Elem()
	dao := daoElem.Interface().(Dao)

	return dao, nil
}

/**
 * 验证新增数据是否存在重复 (一旦使用则覆盖通用方法)
 * @param ctx gin请求对象
 * @param dbEntity 验证数据
 * @return *MsgEmity 返回验证结果
 */
func (service *ServiceBaseFunc) CheckRepeatByAdd(ctx ginutil.Context, dbEntity dbinfo.Entity) *emity.MsgEmity {
	return emity.MsgEmity{}.Success(nil, "验证通过(默认验证通过)")
}

/**
 * 验证更新数据是否存在重复 (一旦使用则覆盖通用方法)
 * @param ctx gin请求对象
 * @param dbEntity 待验证数据
 * @return *MsgEmity 返回验证结果
 */
func (service *ServiceBaseFunc) CheckRepeatByEdit(ctx ginutil.Context, dbEntity dbinfo.Entity) *emity.MsgEmity {
	return emity.MsgEmity{}.Success(nil, "验证通过(默认验证通过)")
}
